//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.activiti.engine.impl.bpmn.helper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.activiti.bpmn.model.BoundaryEvent;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.CallActivity;
import org.activiti.bpmn.model.Error;
import org.activiti.bpmn.model.ErrorEventDefinition;
import org.activiti.bpmn.model.Event;
import org.activiti.bpmn.model.EventSubProcess;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowElementsContainer;
import org.activiti.bpmn.model.MapExceptionEntry;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.engine.impl.util.ReflectUtil;
import org.apache.commons.lang3.StringUtils;

public class ErrorPropagation {
  public ErrorPropagation() {
  }

  public static void propagateError(BpmnError error, DelegateExecution execution) {
    propagateError(error.getErrorCode(), execution);
  }

  public static void propagateError(String errorRef, DelegateExecution execution) {
    Map<String, List<Event>> eventMap = findCatchingEventsForProcess(execution.getProcessDefinitionId(), errorRef);
    if (eventMap.size() > 0) {
      executeCatch(eventMap, execution, errorRef);
    } else if (!execution.getProcessInstanceId().equals(execution.getRootProcessInstanceId())) {
      ExecutionEntityManager executionEntityManager = Context.getCommandContext().getExecutionEntityManager();
      ExecutionEntity processInstanceExecution = (ExecutionEntity)executionEntityManager.findById(execution.getProcessInstanceId());
      if (processInstanceExecution != null) {
        ExecutionEntity parentExecution = processInstanceExecution.getSuperExecution();
        Set<String> toDeleteProcessInstanceIds = new HashSet();
        toDeleteProcessInstanceIds.add(execution.getProcessInstanceId());

        label55:
        while(true) {
          while(true) {
            if (parentExecution == null || eventMap.size() != 0) {
              break label55;
            }

            eventMap = findCatchingEventsForProcess(parentExecution.getProcessDefinitionId(), errorRef);
            if (eventMap.size() > 0) {
              Iterator var10 = toDeleteProcessInstanceIds.iterator();

              while(var10.hasNext()) {
                String processInstanceId = (String)var10.next();
                ExecutionEntity processInstanceEntity = (ExecutionEntity)executionEntityManager.findById(processInstanceId);
                executionEntityManager.deleteProcessInstanceExecutionEntity(processInstanceEntity.getId(), execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getId() : null, "ERROR_EVENT " + errorRef, false, false);
                if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                  Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.PROCESS_COMPLETED_WITH_ERROR_END_EVENT, processInstanceEntity));
                }
              }

              executeCatch(eventMap, parentExecution, errorRef);
            } else {
              toDeleteProcessInstanceIds.add(parentExecution.getProcessInstanceId());
              ExecutionEntity superExecution = parentExecution.getSuperExecution();
              if (superExecution != null) {
                parentExecution = superExecution;
              } else if (!parentExecution.getId().equals(parentExecution.getRootProcessInstanceId())) {
                parentExecution = parentExecution.getProcessInstance();
              } else {
                parentExecution = null;
              }
            }
          }
        }
      }
    }

    if (eventMap.size() == 0) {
      throw new BpmnError(errorRef, "No catching boundary event found for error with errorCode '" + errorRef + "', neither in same process nor in parent process");
    }
  }

  protected static void executeCatch(Map<String, List<Event>> eventMap, DelegateExecution delegateExecution, String errorId) {
    Event matchingEvent = null;
    ExecutionEntity currentExecution = (ExecutionEntity)delegateExecution;
    ExecutionEntity parentExecution = null;
    if (eventMap.containsKey(currentExecution.getActivityId())) {
      matchingEvent = (Event)((List)eventMap.get(currentExecution.getActivityId())).get(0);
      if (currentExecution.getParentId() != null && currentExecution.getParent().isMultiInstanceRoot()) {
        parentExecution = currentExecution.getParent();
      } else {
        parentExecution = currentExecution;
      }
    } else {
      parentExecution = currentExecution.getParent();

      while(matchingEvent == null && parentExecution != null) {
        FlowElementsContainer currentContainer = null;
        if (parentExecution.getCurrentFlowElement() instanceof FlowElementsContainer) {
          currentContainer = (FlowElementsContainer)parentExecution.getCurrentFlowElement();
        } else if (parentExecution.getId().equals(parentExecution.getProcessInstanceId())) {
          currentContainer = ProcessDefinitionUtil.getProcess(parentExecution.getProcessDefinitionId());
        }

        Iterator var7 = eventMap.keySet().iterator();

        while(var7.hasNext()) {
          String refId = (String)var7.next();
          List<Event> events = (List)eventMap.get(refId);
          if (CollectionUtil.isNotEmpty(events) && events.get(0) instanceof StartEvent && ((FlowElementsContainer)currentContainer).getFlowElement(refId) != null) {
            matchingEvent = (Event)events.get(0);
          }
        }

        if (matchingEvent == null) {
          if (eventMap.containsKey(parentExecution.getActivityId())) {
            matchingEvent = (Event)((List)eventMap.get(parentExecution.getActivityId())).get(0);
            if (parentExecution.getParentId() != null && parentExecution.getParent().isMultiInstanceRoot()) {
              parentExecution = parentExecution.getParent();
            }
          } else if (StringUtils.isNotEmpty(parentExecution.getParentId())) {
            parentExecution = parentExecution.getParent();
          } else {
            parentExecution = null;
          }
        }
      }
    }

    if (matchingEvent != null && parentExecution != null) {
      executeEventHandler(matchingEvent, parentExecution, currentExecution, errorId);
    } else {
      throw new ActivitiException("No matching parent execution for error code " + errorId + " found");
    }
  }

  protected static void executeEventHandler(Event event, ExecutionEntity parentExecution, ExecutionEntity currentExecution, String errorId) {
    if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(parentExecution.getProcessDefinitionId());
      if (bpmnModel != null) {
        String errorCode = (String)Optional.ofNullable((Error)bpmnModel.getErrors().get(errorId)).map(Error::getErrorCode).orElse(errorId);
        Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createErrorEvent(ActivitiEventType.ACTIVITY_ERROR_RECEIVED, event.getId(), errorId, errorCode, parentExecution.getId(), parentExecution.getProcessInstanceId(), parentExecution.getProcessDefinitionId()));
      }
    }

    if (event instanceof StartEvent) {
      ExecutionEntityManager executionEntityManager = Context.getCommandContext().getExecutionEntityManager();
      if (!currentExecution.getParentId().equals(parentExecution.getId())) {
        Context.getAgenda().planDestroyScopeOperation(currentExecution);
      } else {
        executionEntityManager.deleteExecutionAndRelatedData(currentExecution, (String)null);
      }

      ExecutionEntity eventSubProcessExecution = executionEntityManager.createChildExecution(parentExecution);
      eventSubProcessExecution.setCurrentFlowElement(event);
      Context.getAgenda().planContinueProcessOperation(eventSubProcessExecution);
    } else {
      ExecutionEntity boundaryExecution = null;
      List<? extends ExecutionEntity> childExecutions = parentExecution.getExecutions();
      Iterator var6 = childExecutions.iterator();

      while(var6.hasNext()) {
        ExecutionEntity childExecution = (ExecutionEntity)var6.next();
        if (childExecution.getActivityId().equals(event.getId())) {
          boundaryExecution = childExecution;
        }
      }

      Context.getAgenda().planTriggerExecutionOperation(boundaryExecution);
    }

  }

  protected static Map<String, List<Event>> findCatchingEventsForProcess(String processDefinitionId, String errorRef) {
    Map<String, List<Event>> eventMap = new HashMap();
    Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
    BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
    String compareErrorCode = retrieveErrorCode(bpmnModel, errorRef);
    List<EventSubProcess> subProcesses = process.findFlowElementsOfType(EventSubProcess.class, true);
    Iterator var7 = subProcesses.iterator();

    ErrorEventDefinition elementBoundaryEvents;
    label84:
    while(var7.hasNext()) {
      EventSubProcess eventSubProcess = (EventSubProcess)var7.next();
      Iterator var9 = eventSubProcess.getFlowElements().iterator();

      while(true) {
        StartEvent startEvent;
        String eventErrorCode;
        do {
          do {
            do {
              FlowElement flowElement;
              do {
                if (!var9.hasNext()) {
                  continue label84;
                }

                flowElement = (FlowElement)var9.next();
              } while(!(flowElement instanceof StartEvent));

              startEvent = (StartEvent)flowElement;
            } while(!CollectionUtil.isNotEmpty(startEvent.getEventDefinitions()));
          } while(!(startEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition));

          elementBoundaryEvents = (ErrorEventDefinition)startEvent.getEventDefinitions().get(0);
          eventErrorCode = retrieveErrorCode(bpmnModel, elementBoundaryEvents.getErrorRef());
        } while(eventErrorCode != null && compareErrorCode != null && !eventErrorCode.equals(compareErrorCode));

        List<Event> startEvents = new ArrayList();
        startEvents.add(startEvent);
        eventMap.put(eventSubProcess.getId(), startEvents);
      }
    }

    List<BoundaryEvent> boundaryEvents = process.findFlowElementsOfType(BoundaryEvent.class, true);
    Iterator var16 = boundaryEvents.iterator();

    while(true) {
      BoundaryEvent boundaryEvent;
      String eventErrorCode;
      do {
        do {
          do {
            do {
              if (!var16.hasNext()) {
                return eventMap;
              }

              boundaryEvent = (BoundaryEvent)var16.next();
            } while(boundaryEvent.getAttachedToRefId() == null);
          } while(!CollectionUtil.isNotEmpty(boundaryEvent.getEventDefinitions()));
        } while(!(boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition));

        ErrorEventDefinition errorEventDef = (ErrorEventDefinition)boundaryEvent.getEventDefinitions().get(0);
        eventErrorCode = retrieveErrorCode(bpmnModel, errorEventDef.getErrorRef());
      } while(eventErrorCode != null && compareErrorCode != null && !eventErrorCode.equals(compareErrorCode));

      elementBoundaryEvents = null;
      Object elementBoundaryEvents2;
      if (!eventMap.containsKey(boundaryEvent.getAttachedToRefId())) {
        elementBoundaryEvents2 = new ArrayList();
        eventMap.put(boundaryEvent.getAttachedToRefId(),(List) elementBoundaryEvents2);
      } else {
        elementBoundaryEvents2 = (List)eventMap.get(boundaryEvent.getAttachedToRefId());
      }

      ((List)elementBoundaryEvents2).add(boundaryEvent);
    }
  }

  public static boolean mapException(Exception e, ExecutionEntity execution, List<MapExceptionEntry> exceptionMap) {
    String errorCode = findMatchingExceptionMapping(e, exceptionMap);
    if (errorCode != null) {
      propagateError((String)errorCode, execution);
      return true;
    } else {
      ExecutionEntity callActivityExecution = null;
      ExecutionEntity parentExecution = execution.getParent();

      while(parentExecution != null && callActivityExecution == null) {
        if (parentExecution.getId().equals(parentExecution.getProcessInstanceId())) {
          if (parentExecution.getSuperExecution() != null) {
            callActivityExecution = parentExecution.getSuperExecution();
          } else {
            parentExecution = null;
          }
        } else {
          parentExecution = parentExecution.getParent();
        }
      }

      if (callActivityExecution != null) {
        CallActivity callActivity = (CallActivity)callActivityExecution.getCurrentFlowElement();
        if (CollectionUtil.isNotEmpty(callActivity.getMapExceptions())) {
          errorCode = findMatchingExceptionMapping(e, callActivity.getMapExceptions());
          if (errorCode != null) {
            propagateError((String)errorCode, callActivityExecution);
            return true;
          }
        }
      }

      return false;
    }
  }

  protected static String findMatchingExceptionMapping(Exception e, List<MapExceptionEntry> exceptionMap) {
    String defaultExceptionMapping = null;
    Iterator var3 = exceptionMap.iterator();

    while(true) {
      while(var3.hasNext()) {
        MapExceptionEntry me = (MapExceptionEntry)var3.next();
        String exceptionClass = me.getClassName();
        String errorCode = me.getErrorCode();
        if (StringUtils.isNotEmpty(errorCode) && StringUtils.isEmpty(exceptionClass) && defaultExceptionMapping == null) {
          defaultExceptionMapping = errorCode;
        } else if (!StringUtils.isEmpty(errorCode) && !StringUtils.isEmpty(exceptionClass)) {
          if (e.getClass().getName().equals(exceptionClass)) {
            return errorCode;
          }

          if (me.isAndChildren()) {
            Class<?> exceptionClassClass = ReflectUtil.loadClass(exceptionClass);
            if (exceptionClassClass.isAssignableFrom(e.getClass())) {
              return errorCode;
            }
          }
        }
      }

      return defaultExceptionMapping;
    }
  }

  protected static String retrieveErrorCode(BpmnModel bpmnModel, String errorRef) {
    return (String)Optional.ofNullable(errorRef).map((ref) -> {
      return bpmnModel.containsErrorRef(errorRef) ? (String)Optional.ofNullable((Error)bpmnModel.getErrors().get(errorRef)).map(Error::getErrorCode).orElse(errorRef) : errorRef;
    }).orElse(errorRef);
  }
}
